Skip to content

fix(integrity): --lock update must regenerate on corrupt lockfile#515

Merged
Kamirus merged 4 commits intocaffeinelabs:mainfrom
ggreif:fix/lock-update-skip-integrity
Apr 23, 2026
Merged

fix(integrity): --lock update must regenerate on corrupt lockfile#515
Kamirus merged 4 commits intocaffeinelabs:mainfrom
ggreif:fix/lock-update-skip-integrity

Conversation

@ggreif
Copy link
Copy Markdown
Contributor

@ggreif ggreif commented Apr 22, 2026

Fixes #514.

What changes for users

mops install --lock update now reliably regenerates mops.lock even when the existing lockfile has a stale or corrupt per-file hash. Previously this case silently no-op'd and then exited 1 on the follow-up integrity check, so --lock update could not recover a broken lock — the only escape hatch was rm mops.lock. That hatch is no longer required.

Default mops install (no flag) is unchanged; the fast-path shortcut still fires when the lockfile's mopsTomlDepsHash matches.

Root cause

updateLockFile short-circuits via checkLockFileLight, which only validates mopsTomlDepsHash. When mops.toml hasn't changed but the lockfile's per-file hashes block is corrupt, the shortcut fires → nothing is rewritten → the subsequent checkLockFile(force) finds the same corrupt hash and calls process.exit(1). Users get "Integrity check failed" with no way out except manual deletion of mops.lock.

Fix

Thread the existing force boolean from checkIntegrity into updateLockFile. force = !!lock is already true exactly when the user explicitly passed --lock update, so:

  • mops install (no flag, outside CI) → force = false, keeps the fast-path
  • mops install --lock updateforce = true, bypasses the light-check shortcut, always regenerates
  • mops install --lock check / --lock ignore → unchanged

Test plan

Added a regression test (--lock update rewrites a lockfile with a corrupt file hash) that:

  1. Runs mops install to produce a valid lockfile.
  2. Surgically replaces one per-file hash with a bogus value.
  3. Runs mops install --lock update.
  4. Asserts exit 0 and that the bogus hash is no longer in the lockfile.

Verified reverting the fix (restoring updateLockFile() / if (checkLockFileLight()) return) makes the new Jest test fail with the expected "Integrity check failed" / "Mismatched hash" error.

Related

`updateLockFile` early-returned whenever `checkLockFileLight` passed,
i.e. whenever `mopsTomlDepsHash` matched. That light check does not
validate the per-file hashes in `mops.lock`, so a lockfile with a
corrupt file-level hash (e.g. one written by a pre-2.12.2 CLI, a
partial/crashed write, or a manual edit) could never be repaired via
`mops install --lock update`: the update no-op'd, the follow-up
`checkLockFile` then failed on the same corrupt hash and exited 1.
The only recovery was `rm mops.lock`.

Thread the existing `force` flag from `checkIntegrity` into
`updateLockFile`. When the user explicitly passes `--lock update`,
skip the light-check shortcut and unconditionally regenerate. Default
`mops install` (no flag) still hits the fast path.

Add a regression test that corrupts one per-file hash and asserts
`install --lock update` rewrites the lock to a non-corrupt state.

Fixes caffeinelabs#514.
@ggreif ggreif requested a review from a team as a code owner April 22, 2026 20:37
@ggreif
Copy link
Copy Markdown
Contributor Author

ggreif commented Apr 22, 2026

An independent TS-savvy review flagged one framing question worth surfacing for discussion, @Kamirus:

Narrow fix vs. widening checkLockFileLight

This PR deliberately scopes to the explicit-force path — --lock update now honours its contract. The default mops install still takes the fast-path shortcut on a corrupt lockfile and only fails at the subsequent checkLockFile.

The alternative framing would be to make checkLockFileLight honest: have it validate per-file hashes too, so the short-circuit is trustworthy for all callers, not just --lock update. Then any install/add/remove/sync/update flow would also self-heal a corrupt lock without needing --lock update.

Trade-offs:

Happy to either (a) leave this PR as-is and file a follow-up issue for the widening, or (b) swap this PR for the wider fix if you'd prefer. No strong opinion on my side — your call.

Kamirus and others added 2 commits April 23, 2026 09:53
… fails

When `checkLockFile` exits on a per-file hash mismatch, point users at
the now-working `--lock update` recovery flag. Without this hint, users
hitting caffeinelabs#514 had no in-product signal that the escape hatch existed.

Also document the recovery use case in `mops install --lock` docs.

Made-with: Cursor
@Kamirus Kamirus enabled auto-merge (squash) April 23, 2026 07:54
@Kamirus Kamirus merged commit 15e4b81 into caffeinelabs:main Apr 23, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mops install --lock update does not rewrite a lockfile with a stale/corrupt hash

2 participants